function Observer(data) {
    // 保存data
    this.data = data;
    // 启动对data对象中数据的劫持
    this.walk(data);  // startup
}

Observer.prototype = {
    walk: function(data) {
        var me = this;
        // 遍历data的所有属性
        Object.keys(data).forEach(function(key) {
            // 将data中属性重新定义的响应式
            me.defineReactive(data, key, data[key])
        });
    },

    defineReactive: function(data, key, val) {
        // 创建一个对应的dep对象(订阅器/中间人)
        var dep = new Dep();  // depend(依赖)
        // 通过隐式递归调用实现所有层次属性的监视/劫持
        observe(val);

        // 给data重新定义属性, 添加setter/getter
        Object.defineProperty(data, key, {
            enumerable: true, // 可枚举
            configurable: false, // 不能再define
            // 收集依赖
            get: function() { // 收集依赖: 将watcher添加到对应的dep中(subs) 

                // 用于建立dep与watcher的关系
                if (Dep.target) {
                    dep.depend();
                }
                return val;
            },

            // 派发更新
            // this.msg = 'abc' => 数据代理 => data.msg = 'abc'
            set: function(newVal) {
                if (newVal === val) {
                    return;
                }
                val = newVal;
                // 偿试监视新的值的内部数据
                childObj = observe(newVal);
                // 派发更新
                dep.notify();
            }
        });
    }
};

function observe(value, vm) {

    if (!value || typeof value !== 'object') {
        return;
    }
    // 创建一个对应的observer对象
    return new Observer(value);
};


var uid = 0;

// Depend: 依赖收集
function Dep() { // 对就一个属性
    this.id = uid++;
    this.subs = []; // 保存watcher的数组 ==> 当属性在多个表达式使用时有多个watcher
    // subscribers  publish /subscribers   
    // subscribers  watcher
  
}

Dep.prototype = {
    addSub: function(sub) {
        this.subs.push(sub);
    },

    depend: function() {
        Dep.target.addDep(this);
    },

    removeSub: function(sub) {
        var index = this.subs.indexOf(sub);
        if (index != -1) {
            this.subs.splice(index, 1);
        }
    },

    notify: function() {
        // 遍历每个订阅者watcher
        this.subs.forEach(function(sub) { // subcriber
            // 去更新对应的节点
            sub.update();
        });
    }
};

Dep.target = null;